Link do źródła danych: https://www.kaggle.com/sanjeetsinghnaik/football-data-top-5-leagues
Liga której dotyczy moja praca: Bundesliga
Dane dotyczą okresu 2016-2020
# import bibliotek i wczytanie danych z pliku .csv
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
import plotly.express as px
import plotly.graph_objects as go
import matplotlib.ticker
import plotly.offline
plotly.offline.init_notebook_mode() # aby zapisać wykresy utworzone za pomocą plotly
plt.style.use('seaborn')
sns.set(font_scale=1)
sns.set(rc={'figure.figsize':(11.7,8.27)})
df = pd.read_csv('bundesliga.csv')
Jako, że drużyny grają jako gospodarze i goście, trzeba będzie uwzlędnić to w programie.
df1 = df.copy() # użycie copy jest bezpieczniejsze - mamy pewność, że nie nadpiszemy oryginału.
dataShotsGoals = df1[['Home Team', 'Away Team', 'Home Team Total Shots', 'Away Team Total Shots', 'Home Team Goals Scored', 'Away Team Goals Scored']].copy()
# Aby podsumować bramki strzelone przez daną drużynę trzeba uwzględnić strzelone zarówno w domu, jak i na wyjeździe.
dataShotsGoals_home = df1[['Home Team', 'Home Team Total Shots', 'Home Team Goals Scored']].copy().rename(columns={'Home Team': 'Drużyna', 'Home Team Total Shots': 'Strzały', 'Home Team Goals Scored': 'Bramki' })
dataShotsGoals_away = df1[['Away Team', 'Away Team Total Shots', 'Away Team Goals Scored']].copy().rename(columns={'Away Team': 'Drużyna', 'Away Team Total Shots': 'Strzały', 'Away Team Goals Scored': 'Bramki' })
# Informacje potrzebne do wykresu nr 3
dataShotsGoals_home['Teren'] = 'U siebie'
dataShotsGoals_away['Teren'] = 'Wyjazdowy'
# Aby złączyć tablice należy użyć .concat().
dataShotsGoals_cat = pd.concat([dataShotsGoals_home, dataShotsGoals_away])
dataShotsGoals_cat['Strzały'] = dataShotsGoals_cat['Strzały'].astype(int) # zmieniamy typ wyświetlanych danych na int, ponieważ domyślnie jest typ zmiennoprzecinkowy, co w tym przypadku nie ma sensu.
# Na koniec wystarczy posortować względem drużyny, dodać kolumnę gdzie będzie liczona skuteczność i wyświetlić wynik końcowy.
sortedShotsGoals = dataShotsGoals_cat.groupby('Drużyna').sum().reset_index() # grupujemy nasz wynik likwidując duplikaty drużyn.
chart1Data = sortedShotsGoals.copy() # dane potrzebne do pierwszego wykresu, kopia dokonana jest w tym momencie, ponieważ na wykresie nie będziemy potrzebować danych o skuteczności.
sortedShotsGoals['Skuteczność (%)'] = (sortedShotsGoals['Bramki'] / sortedShotsGoals['Strzały'] * 100).round(2) # wyliczenie skuteczności, czyli stosunku bramek do oddanych strzałów.
sortedShotsGoals
| Drużyna | Strzały | Bramki | Skuteczność (%) | |
|---|---|---|---|---|
| 0 | 1. FC KÖLN | 1524 | 171 | 11.22 |
| 1 | AUGSBURG | 1958 | 210 | 10.73 |
| 2 | BAYERN | 3058 | 468 | 15.30 |
| 3 | BIELEFELD | 335 | 26 | 7.76 |
| 4 | DARMSTADT | 341 | 28 | 8.21 |
| 5 | DORTMUND | 2404 | 376 | 15.64 |
| 6 | DÜSSELDORF | 846 | 85 | 10.05 |
| 7 | FRANKFURT | 2141 | 269 | 12.56 |
| 8 | FREIBURG | 2053 | 220 | 10.72 |
| 9 | HANNOVER | 820 | 75 | 9.15 |
| 10 | HERTHA | 1814 | 224 | 12.35 |
| 11 | HOFFENHEIM | 2466 | 305 | 12.37 |
| 12 | HSV | 755 | 62 | 8.21 |
| 13 | INGOLSTADT | 455 | 36 | 7.91 |
| 14 | LEVERKUSEN | 2410 | 294 | 12.20 |
| 15 | M'GLADBACH | 2260 | 277 | 12.26 |
| 16 | MAINZ | 2159 | 211 | 9.77 |
| 17 | NÜRNBERG | 360 | 26 | 7.22 |
| 18 | PADERBORN | 431 | 37 | 8.58 |
| 19 | RB LEIPZIG | 2519 | 327 | 12.98 |
| 20 | SCHALKE | 1951 | 198 | 10.15 |
| 21 | STUTTGART | 1229 | 124 | 10.09 |
| 22 | UNION BERLIN | 800 | 91 | 11.38 |
| 23 | W. BREMEN | 2070 | 234 | 11.30 |
| 24 | WOLFSBURG | 2164 | 241 | 11.14 |
Ranking najbardziej faulujących drużyn.
df2 = df.copy()
dataFouls = df2[['Home Team', 'Away Team', 'Home Team Fouls', 'Away Team Fouls', 'Home Team Yellow Cards', 'Away Team Yellow Cards', 'Home Team Red Cards', 'Away Team Red Cards']].copy()
# Tak jak poprzednio, dzielimy bazę na gospodarzy i gości, aby potem ją połączyć i zebrać poprawnie dane.
dataFouls_home = df2[['Home Team', 'Home Team Fouls', 'Home Team Yellow Cards', 'Home Team Red Cards']].copy().rename(columns={'Home Team': 'Drużyna', 'Home Team Fouls': 'Faule', 'Home Team Yellow Cards': 'Żółte kartki', 'Home Team Red Cards': 'Czerwone kartki' })
dataFouls_away = df2[['Away Team', 'Away Team Fouls', 'Away Team Yellow Cards', 'Away Team Red Cards']].copy().rename(columns={'Away Team': 'Drużyna', 'Away Team Fouls': 'Faule', 'Away Team Yellow Cards': 'Żółte kartki', 'Away Team Red Cards': 'Czerwone kartki' })
# Aby złączyć tablice należy użyć .concat().
dataFouls_cat = pd.concat([dataFouls_home, dataFouls_away])
# Na koniec wystarczy posortować względem drużyny, dodać kolumnę gdzie będzie liczona skuteczność i wyświetlić wynik końcowy.
groupedFouls = dataFouls_cat.groupby('Drużyna').sum().reset_index() # grupujemy nasz wynik likwidując duplikaty drużyn
sortedFouls = groupedFouls.sort_values(by='Faule', ascending=False) # chcemy sortować od największych do najmniejszych ilości, dlatego ascending ustawiamy na False
sortedFouls['Faule'] = sortedFouls['Faule'].astype(int)
sortedFouls['Żółte kartki'] = sortedFouls['Żółte kartki'].astype(int)
sortedFouls['Czerwone kartki'] = sortedFouls['Czerwone kartki'].astype(int)
sortedFouls
| Drużyna | Faule | Żółte kartki | Czerwone kartki | |
|---|---|---|---|---|
| 16 | MAINZ | 2418 | 322 | 6 |
| 7 | FRANKFURT | 2367 | 365 | 10 |
| 10 | HERTHA | 2357 | 318 | 8 |
| 20 | SCHALKE | 2325 | 341 | 9 |
| 11 | HOFFENHEIM | 2316 | 332 | 4 |
| 23 | W. BREMEN | 2291 | 324 | 3 |
| 24 | WOLFSBURG | 2249 | 314 | 6 |
| 19 | RB LEIPZIG | 2249 | 280 | 5 |
| 1 | AUGSBURG | 2216 | 324 | 4 |
| 14 | LEVERKUSEN | 2122 | 275 | 8 |
| 8 | FREIBURG | 2069 | 267 | 4 |
| 15 | M'GLADBACH | 1968 | 273 | 2 |
| 0 | 1. FC KÖLN | 1860 | 281 | 3 |
| 5 | DORTMUND | 1772 | 227 | 6 |
| 2 | BAYERN | 1677 | 227 | 4 |
| 21 | STUTTGART | 1255 | 185 | 4 |
| 12 | HSV | 1063 | 135 | 4 |
| 22 | UNION BERLIN | 955 | 124 | 3 |
| 9 | HANNOVER | 908 | 124 | 1 |
| 6 | DÜSSELDORF | 839 | 145 | 1 |
| 13 | INGOLSTADT | 555 | 72 | 3 |
| 4 | DARMSTADT | 515 | 71 | 0 |
| 18 | PADERBORN | 426 | 82 | 1 |
| 17 | NÜRNBERG | 394 | 58 | 3 |
| 3 | BIELEFELD | 390 | 52 | 1 |
Na podstawie "Match Excitement"
df3 = df[df['year']==2020].copy()
df3 = df3[['Home Team', 'Away Team', 'Score', 'Match Excitement']].rename(columns={'Home Team': 'Drużyna gospodarzy', 'Away Team': 'Drużyna gości', 'Score': "Wynik końcowy", 'Match Excitement': 'Poziom ekscytacji (0-10)'})
sortedByExcitement = df3.sort_values(by='Poziom ekscytacji (0-10)', ascending=False)
sortedByExcitement.head(10)
| Drużyna gospodarzy | Drużyna gości | Wynik końcowy | Poziom ekscytacji (0-10) | |
|---|---|---|---|---|
| 1287 | HOFFENHEIM | STUTTGART | 3-3 | 10.0 |
| 1516 | SCHALKE | FRANKFURT | 4-3 | 10.0 |
| 1250 | BAYERN | HERTHA | 4-3 | 10.0 |
| 1286 | LEVERKUSEN | M'GLADBACH | 4-3 | 9.8 |
| 1468 | FRANKFURT | WOLFSBURG | 4-3 | 9.8 |
| 1262 | MAINZ | M'GLADBACH | 2-3 | 9.7 |
| 1411 | BAYERN | BIELEFELD | 3-3 | 9.5 |
| 1527 | BAYERN | AUGSBURG | 5-2 | 9.4 |
| 1348 | BAYERN | MAINZ | 5-2 | 9.2 |
| 1225 | 1. FC KÖLN | HOFFENHEIM | 2-3 | 9.1 |
Dane ze wszystkich lat mogłyby zaburzyć wnioski - nie wszystkie drużyny się utrzymały w Bundeslidze, przez co ich ilośc spotkań i wygranych meczów byłaby znacznie niższa.
Wniosek: Drużyny, które mają większe posiadanie piłki wygrywają więcej spotkań.
df4 = df[df['year']==2016].copy() # użycie copy jest bezpieczniejsze - mamy pewność, że nie nadpiszemy oryginału.
dataPossession = df4[['Home Team', 'Away Team', 'Home Team Possession %', 'Away Team Possession %', 'Home Team Goals Scored', 'Away Team Goals Scored']].copy()
dataPossession.reset_index() # resetujemy indeksy, aby przeprowadzić iteracje
# tworzymy nowe dane o rezultacie spotkań na podstawie ilości bramek
dataPossession['Home Wins'] = np.where(dataPossession['Home Team Goals Scored'] > dataPossession['Away Team Goals Scored'], 1, 0)
dataPossession['Home Loses'] = np.where(dataPossession['Home Team Goals Scored'] < dataPossession['Away Team Goals Scored'], 1, 0)
dataPossession['Home Draws'] = np.where(dataPossession['Home Team Goals Scored'] == dataPossession['Away Team Goals Scored'], 1, 0)
dataPossession['Away Draws'] = np.where(dataPossession['Home Team Goals Scored'] == dataPossession['Away Team Goals Scored'], 1, 0)
dataPossession['Away Loses'] = np.where(dataPossession['Home Team Goals Scored'] > dataPossession['Away Team Goals Scored'], 1, 0)
dataPossession['Away Wins'] = np.where(dataPossession['Home Team Goals Scored'] < dataPossession['Away Team Goals Scored'], 1, 0)
dataPossession_home = dataPossession[['Home Team', 'Home Team Possession %', 'Home Wins', 'Home Draws', 'Home Loses']].copy().rename(columns={'Home Team': 'Drużyna', 'Home Team Possession %': 'Posiadanie piłki (%)', 'Home Wins': 'Wygrane', 'Home Draws': 'Remisy', 'Home Loses': 'Przegrane' })
dataPossession_away = dataPossession[['Away Team', 'Away Team Possession %', 'Away Wins', 'Away Draws', 'Away Loses']].copy().rename(columns={'Away Team': 'Drużyna', 'Away Team Possession %': 'Posiadanie piłki (%)', 'Away Wins': 'Wygrane', 'Away Draws': 'Remisy', 'Away Loses': 'Przegrane' })
# Aby złączyć tablice należy użyć .concat().
dataPossession_cat = pd.concat([dataPossession_home, dataPossession_away])
# # Na koniec wystarczy posortować względem drużyny, dodać kolumnę gdzie będzie liczona skuteczność i wyświetlić wynik końcowy.
groupedPossession = dataPossession_cat.groupby('Drużyna').sum().reset_index() # grupujemy nasz wynik likwidując duplikaty drużyn.
sortedPossession = groupedPossession.sort_values(by='Posiadanie piłki (%)', ascending=False) # chcemy sortować od największych do najmniejszych ilości, dlatego ascending ustawiamy na False
# wyliczenie ilości rozegranych spotkań, która wynosi 34 dla wszystkich drużyn (dla pewności i łatwego wyliczenia średniego posiadania piłki)
# sortedPossession['Ilość rozegranych meczów'] = (sortedPossession['Wygrane'] + sortedPossession['Remisy'] + sortedPossession['Przegrane'])
sortedPossession['Posiadanie piłki (%)'] = (sortedPossession['Posiadanie piłki (%)'] / 34).round(2) # dzielimy sumę procentów posiadania piłki przez ilość rozegranych spotkań
sortedPossession
| Drużyna | Posiadanie piłki (%) | Wygrane | Remisy | Przegrane | |
|---|---|---|---|---|---|
| 2 | BAYERN | 68.91 | 25 | 7 | 2 |
| 4 | DORTMUND | 62.00 | 18 | 10 | 6 |
| 8 | HOFFENHEIM | 56.24 | 16 | 14 | 4 |
| 11 | LEVERKUSEN | 54.18 | 11 | 8 | 15 |
| 12 | M'GLADBACH | 53.85 | 12 | 9 | 13 |
| 14 | RB LEIPZIG | 52.97 | 20 | 7 | 7 |
| 15 | SCHALKE | 51.71 | 11 | 10 | 13 |
| 17 | WOLFSBURG | 51.62 | 10 | 7 | 17 |
| 5 | FRANKFURT | 49.88 | 11 | 9 | 14 |
| 7 | HERTHA | 48.50 | 15 | 4 | 15 |
| 6 | FREIBURG | 46.68 | 14 | 6 | 14 |
| 10 | INGOLSTADT | 45.97 | 8 | 8 | 18 |
| 13 | MAINZ | 45.88 | 10 | 7 | 17 |
| 16 | W. BREMEN | 44.56 | 13 | 6 | 15 |
| 9 | HSV | 43.74 | 10 | 8 | 16 |
| 0 | 1. FC KÖLN | 43.32 | 12 | 13 | 9 |
| 1 | AUGSBURG | 41.76 | 9 | 11 | 14 |
| 3 | DARMSTADT | 38.24 | 7 | 4 | 23 |
Zestawienie bardzo podobne do poprzedniego, jednak warte uwagi.
Wniosek: Drużyny, których podania kończą się częściej sukcesem wygrywają więcej spotkań.
df5 = df[df['year']==2018].copy() # użycie copy jest bezpieczniejsze - mamy pewność, że nie nadpiszemy oryginału.
dataPassSuccess = df5[['Home Team', 'Away Team', 'Home Team Pass Success %', 'Away Team Pass Success %', 'Home Team Goals Scored', 'Away Team Goals Scored']].copy()
dataPassSuccess.reset_index() # resetujemy indeksy, aby przeprowadzić iteracje
# tworzymy nowe dane o rezultacie spotkań na podstawie ilości bramek
dataPassSuccess['Home Wins'] = np.where(dataPassSuccess['Home Team Goals Scored'] > dataPassSuccess['Away Team Goals Scored'], 1, 0)
dataPassSuccess['Home Loses'] = np.where(dataPassSuccess['Home Team Goals Scored'] < dataPassSuccess['Away Team Goals Scored'], 1, 0)
dataPassSuccess['Home Draws'] = np.where(dataPassSuccess['Home Team Goals Scored'] == dataPassSuccess['Away Team Goals Scored'], 1, 0)
dataPassSuccess['Away Draws'] = np.where(dataPassSuccess['Home Team Goals Scored'] == dataPassSuccess['Away Team Goals Scored'], 1, 0)
dataPassSuccess['Away Loses'] = np.where(dataPassSuccess['Home Team Goals Scored'] > dataPassSuccess['Away Team Goals Scored'], 1, 0)
dataPassSuccess['Away Wins'] = np.where(dataPassSuccess['Home Team Goals Scored'] < dataPassSuccess['Away Team Goals Scored'], 1, 0)
dataPassSuccess_home = dataPassSuccess[['Home Team', 'Home Team Pass Success %', 'Home Wins', 'Home Draws', 'Home Loses']].copy().rename(columns={'Home Team': 'Drużyna', 'Home Team Pass Success %': 'Udane podania (%)', 'Home Wins': 'Wygrane', 'Home Draws': 'Remisy', 'Home Loses': 'Przegrane' })
dataPassSuccess_away = dataPassSuccess[['Away Team', 'Away Team Pass Success %', 'Away Wins', 'Away Draws', 'Away Loses']].copy().rename(columns={'Away Team': 'Drużyna', 'Away Team Pass Success %': 'Udane podania (%)', 'Away Wins': 'Wygrane', 'Away Draws': 'Remisy', 'Away Loses': 'Przegrane' })
# Aby złączyć tablice należy użyć .concat().
dataPassSuccess_cat = pd.concat([dataPassSuccess_home, dataPassSuccess_away])
# # Na koniec wystarczy posortować względem drużyny, dodać kolumnę gdzie będzie liczona skuteczność i wyświetlić wynik końcowy.
groupedPassSuccess = dataPassSuccess_cat.groupby('Drużyna').sum().reset_index() # grupujemy nasz wynik likwidując duplikaty drużyn.
sortedPassSuccess = groupedPassSuccess.sort_values(by='Udane podania (%)', ascending=False) # chcemy sortować od największych do najmniejszych ilości, dlatego ascending ustawiamy na False
# wyliczenie ilości rozegranych spotkań, która wynosi 34 dla wszystkich drużyn (dla pewności i łatwego wyliczenia średniego posiadania piłki)
# sortedPassSuccess['Ilość rozegranych meczów'] = (sortedPassSuccess['Wygrane'] + sortedPassSuccess['Remisy'] + sortedPassSuccess['Przegrane'])
sortedPassSuccess['Udane podania (%)'] = (sortedPassSuccess['Udane podania (%)'] / 34).round(2) # dzielimy sumę procentów posiadania piłki przez ilość rozegranych spotkań
sortedPassSuccess
| Drużyna | Udane podania (%) | Wygrane | Remisy | Przegrane | |
|---|---|---|---|---|---|
| 1 | BAYERN | 87.06 | 24 | 6 | 4 |
| 2 | DORTMUND | 85.21 | 23 | 7 | 4 |
| 10 | M'GLADBACH | 83.53 | 16 | 7 | 11 |
| 9 | LEVERKUSEN | 83.12 | 18 | 4 | 12 |
| 8 | HOFFENHEIM | 81.32 | 13 | 12 | 9 |
| 16 | W. BREMEN | 79.06 | 14 | 11 | 9 |
| 17 | WOLFSBURG | 78.26 | 16 | 7 | 11 |
| 7 | HERTHA | 77.71 | 11 | 10 | 13 |
| 5 | FREIBURG | 76.76 | 8 | 12 | 14 |
| 11 | MAINZ | 76.38 | 12 | 7 | 15 |
| 3 | DÜSSELDORF | 76.06 | 13 | 5 | 16 |
| 6 | HANNOVER | 75.85 | 5 | 6 | 23 |
| 14 | SCHALKE | 75.41 | 8 | 9 | 17 |
| 12 | NÜRNBERG | 74.91 | 3 | 10 | 21 |
| 15 | STUTTGART | 74.68 | 7 | 7 | 20 |
| 13 | RB LEIPZIG | 74.65 | 19 | 9 | 6 |
| 0 | AUGSBURG | 73.53 | 8 | 8 | 18 |
| 4 | FRANKFURT | 72.35 | 15 | 9 | 10 |
Wniosek: Bardzo mało strzałów kończy się bramką, dlatego bramki w tym sporcie są tak wyjątkowe.
# Aby pokazać strzały i bramki na tym samym wykresie musimy zmienić układ danych za pomocą .melt()
chart1Data_melt = pd.melt(chart1Data, id_vars=['Drużyna'], value_vars=['Strzały', 'Bramki'], var_name="Rodzaj", value_name="Wartość")
ax1 = sns.barplot(x="Drużyna", y="Wartość", hue="Rodzaj", data=chart1Data_melt)
ax1.set_xticklabels(ax1.get_xticklabels(), rotation=90)
ax1.set_title('Bramki i strzały w 2016-2020')
None # dzięki temu unikamy wyjścia w formie tekstowej
Wniosek: Gospodarze zazwyczaj lepiej wypadają w spotkaniach.
chart2Data = df.groupby(by=['year'])
disp2 = chart2Data.mean() # wyliczamy średnią wartość dla kolumn znajdujących się w zestawie
fig, ax2 = plt.subplots(figsize=(10,8))
ax2.plot(chart2Data['Home Team Rating'].mean(), marker='.', label='Gospodarze')
ax2.plot(chart2Data['Away Team Rating'].mean(), marker='.', label='Goście')
# Rok wyświetlał się niepoprawnie (zamiast 2016 było 2016.0) przez co trzeba było rozwiązać to w następujący sposób:
locator = matplotlib.ticker.MultipleLocator(1) # przesunięcie na osi x
plt.gca().xaxis.set_major_locator(locator)
plt.xlim([2016, 2020]) # ustalenie granic wykresu na osi x
plt.xlabel("Rok")
plt.ylabel("Wartość oceny (0-10)")
plt.title("Oceny gospodarzy vs oceny gości w konkretnych latach")
plt.legend()
None # dzięki temu unikamy wyjścia w formie tekstowej
Wniosek: Zawodnicy na swoim terenie oddają więcej strzałów co świadczy o tym, że są pewniejsi siebie, grają agresywniej.
plt.figure(figsize=(15,5))
ax3 = sns.barplot(x="Drużyna", y="Strzały", hue="Teren", data=dataShotsGoals_cat, ci=0) # dane z zestawienia nr 1
ax3.set_xticklabels(ax3.get_xticklabels(), rotation=90)
ax3.set_title('Strzały oddane przez drużyny względem miejsca spotkania')
None # dzięki temu unikamy wyjścia w formie tekstowej
chart4Data = df[['Home Team Off Target Shots', 'Home Team On Target Shots', 'Home Team Blocked Shots', 'Away Team Off Target Shots', 'Away Team On Target Shots', 'Away Team Blocked Shots']].copy()
chart4Data_home = chart4Data[['Home Team Off Target Shots', 'Home Team On Target Shots', 'Home Team Blocked Shots']].copy().rename(columns={'Home Team Off Target Shots': 'Strzały niecelne', 'Home Team On Target Shots': "Strzały celne", 'Home Team Blocked Shots': 'Strzały zablokowane' })
chart4Data_away = chart4Data[['Away Team Off Target Shots', 'Away Team On Target Shots', 'Away Team Blocked Shots']].copy().rename(columns={'Away Team Off Target Shots': 'Strzały niecelne', 'Away Team On Target Shots': 'Strzały celne', 'Away Team Blocked Shots': 'Strzały zablokowane' })
chart4Data_cat = pd.concat([chart4Data_home, chart4Data_away]).sum()
labels = ['Strzały niecelne','Strzały celne','Strzały zablokowane']
values = [chart4Data_cat['Strzały niecelne'], chart4Data_cat['Strzały celne'], chart4Data_cat['Strzały zablokowane']]
fig4 = px.pie(values=values, names=labels, color_discrete_sequence=px.colors.sequential.Blackbody, width=800, height=400, title='Dane dotyczące rodzajów strzałów w Bundeslidze na przestrzeni lat 2016-2020')
fig4.show()
Wniosek: Zdecydowana większość przewinień nie jest karana, natomiast czerwone kartki to wyjątkowa rzadkość.
chart5Data = df[['Home Team Fouls', 'Home Team Yellow Cards', 'Home Team Red Cards', 'Away Team Fouls', 'Away Team Yellow Cards', 'Away Team Red Cards']].copy()
chart5Data_home = chart5Data[['Home Team Fouls', 'Home Team Yellow Cards', 'Home Team Red Cards']].copy().rename(columns={'Home Team Fouls': 'Faule bez kary', 'Home Team Yellow Cards': "Żółte kartki", 'Home Team Red Cards': 'Czerwone kartki' })
chart5Data_away = chart5Data[['Away Team Fouls', 'Away Team Yellow Cards', 'Away Team Red Cards']].copy().rename(columns={'Away Team Fouls': 'Faule bez kary', 'Away Team Yellow Cards': "Żółte kartki", 'Away Team Red Cards': 'Czerwone kartki' })
chart5Data_cat = pd.concat([chart5Data_home, chart5Data_away]).sum()
# jako, że 'Fouls' w zestawie danych to suma wszystkich fauli, należy obliczyć faule bez kary odejmując od sumy wszystkich faule zakończone karą
chart5Data_cat['Faule bez kary'] = chart5Data_cat['Faule bez kary'] - (chart5Data_cat['Żółte kartki'] + chart5Data_cat['Czerwone kartki'])
labels = ['Faule bez kary','Żółte kartki','Czerwone kartki']
values = [chart5Data_cat['Faule bez kary'], chart5Data_cat['Żółte kartki'], chart5Data_cat['Czerwone kartki']]
fig5 = px.pie(values=values, names=labels, color_discrete_sequence=px.colors.sequential.Emrld, width=800, height=400, title='Dane dotyczące fauli i kar dla drużyn w Bundeslidze na przestrzeni lat 2016-2020')
fig5.show()